/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package avl.sv.shared.Annotations;

import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.geom.PathIterator;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author benbryan
 */
public class ROIOval extends ROI implements Serializable, Cloneable {
    public Ellipse2D.Double oval;
    public Creating creating;
    public static final int TYPE = 2;
    public ArrayList<Point> parsingPoints;

    public ROIOval() {
    }

    public ROIOval(int centerX, int centerY, int width, int height) {
        attributes = new ArrayList<>();
        text = "default name";
        selectedPoints = new ArrayList<>();
        
        oval = new Ellipse2D.Double();
        oval.x = centerX-width/2;
        oval.y = centerY-height/2;
        oval.height = height;
        oval.width = width;
        creating = Creating.CREATED;
    }
    
    public ROIOval(int centerX, int centerY) {
        attributes = new ArrayList<>();
        text = "default name";
        selectedPoints = new ArrayList<>();
        
        oval = new Ellipse2D.Double();
        oval.x = centerX;
        oval.y = centerY;
        creating = Creating.MANUAL;
    }
    
    public static ROIOval getDefault() {
        ROIOval r = new ROIOval();
        r.attributes = new ArrayList<>();
        r.text = "default name";
        r.selectedPoints = new ArrayList<>();
        r.oval = new Ellipse2D.Double();
        r.creating = Creating.PARSING;
        return r;
    }
    
    @Override
    public void addPoint(double x, double y) {
        addPoint((int)x, (int)y);
    }
    
    public enum Creating {
        CREATED, MANUAL, PARSING 
    }
              
    @Override
    public void addPoint(int nx, int ny) {
        addSecondPoint(nx, ny);
    }
 
    public boolean addSecondPoint(int nx, int ny){
        if (creating == Creating.CREATED){
            return false;
        } else if (creating == Creating.MANUAL) {
            double centerX = oval.x + oval.width / 2;
            double centerY = oval.y + oval.height / 2;
            double width = 2*Math.abs(centerX-nx);
            double height = 2*Math.abs(centerY-ny);
            oval.x = centerX-width/2;
            oval.y = centerY-height/2;
            oval.height = height;
            oval.width = width;
            return true;
        } else if (creating == Creating.PARSING) {
            if (parsingPoints == null){
                parsingPoints = new ArrayList<>();
            }
            parsingPoints.add(new Point(nx, ny));
            if (parsingPoints.size() == 4){
                oval.x = parsingPoints.get(2).x;
                oval.y = parsingPoints.get(0).y;
                oval.width = parsingPoints.get(1).x - oval.x;
                oval.height = parsingPoints.get(3).y - oval.y;
                creating = Creating.CREATED;
                return true;
            }
            return true;
        } else {
            return false;
        }
    }
    
    public void closeOval(){
        creating = Creating.CREATED;
    }
    
    @Override
    public Polygon getPolygon(AffineTransform at){  
        Polygon p = new Polygon();
        double x = oval.x;
        double y = oval.y;
        double w = oval.width;
        double h = oval.height;
        p.addPoint((int)(x+w/2), (int)(y));
        p.addPoint((int)(x+w), (int)(y+h/2));
        p.addPoint((int)(x), (int)(y+h/2));
        p.addPoint((int)(x+w/2), (int)(y+h));
        return p;
    }
    
    @Override
    public void changePoint(int index, double nx, double ny){
        changePoint(index, (int) nx, (int) ny);
    }
    
    @Override
    public void changePoint(int index, int nx, int ny) {
        double x = oval.x;
        double y = oval.y;
        double w = oval.width;
        double h = oval.height;
        Point pn = new Point(nx, ny);
        Point ps[] = new Point[]{
            new Point((int)(x+w/2), (int)(y)),
            new Point((int)(x+w), (int)(y+h/2)),
            new Point((int)(x), (int)(y+h/2)),
            new Point((int)(x+w/2), (int)(y+h))};
        double bestDist = java.lang.Double.MAX_VALUE;
        int bestIdx = -1;
        for (int i = 0; i < ps.length; i++){
            double dist = pn.distance(ps[i]);
            if (bestDist > dist){
                bestDist = dist;
                bestIdx = i;
            }
        }
        double dy, dx;
        switch (bestIdx){
            case 0:
                //Fix 3, Mod y & h
                dy = ps[0].y - ny;
                oval.height += dy;
                oval.y = y-dy;
                break;
            case 1:
                //Fix 2, Mod x & w
                dx = ps[1].x - nx;
                oval.width -= dx;
                break;
            case 2:
                //Fix 1, Mod x & w
                dx = ps[2].x - nx;
                oval.width += dx;
                oval.x = x-dx;
                break;
            case 3:
                //Fix 0, Mod y & h
                dy = ps[3].y - ny;
                oval.height -= dy;
                break;
        }
    }

    @Override
    public boolean containsPoint(int x, int y) {
        return oval.contains(x, y);
    }    
    
    @Override
    public boolean containsPoint(Point p) {
        return oval.contains(p);
    }

    @Override
    public Shape getShape() {
        return oval;
    }

    @Override
    public int getType() {
        return TYPE;
    }
    
    
    @Override
    public Object clone() {
        ROIOval temp = (ROIOval) super.clone();
        temp.oval = (Ellipse2D.Double) oval.clone();
        return temp;
    }
    
}
